import { useRef, useEffect } from 'react';
import { useCanvasKit } from '../contexts/CanvasKitContext';
import { useTextRendering } from '../contexts/TextRenderingContext';
import { useEditor } from '../contexts/EditorContext';

/**
 * Pure rendering component that draws text on canvas using CanvasKit
 * Maintains no state - purely reactive to context changes
 */
const TextRenderer = ({ 
  canvasRef, 
  width = 500, 
  height = 500,
  style = {}
}) => {
  const {
    CanvasKit,
    canvasKitInstance,
    surfaceRef,
    createSurface,
    canvasKitStatus
  } = useCanvasKit();

  const {
    fontSize,
    letterSpacing,
    getCurrentFont,
    analyzeTextLineBreaks,
    isReady: renderingReady
  } = useTextRendering();

  const {
    text,
    cursorPosition,
    isFocused,
    renderTrigger
  } = useEditor();

  // Track DPR changes to recreate surface when needed
  const dprRef = useRef(window.devicePixelRatio || 1);

  // Initialize canvas surface when CanvasKit is ready
  useEffect(() => {
    if (canvasKitStatus === 'ready' && canvasRef.current && !surfaceRef.current) {
      createSurface(canvasRef.current);
    }
  }, [canvasKitStatus, createSurface, canvasRef]);

  // Handle DPR changes and recreate surface if needed
  useEffect(() => {
    const currentDpr = window.devicePixelRatio || 1;
    if (currentDpr !== dprRef.current && surfaceRef.current) {
      console.log(`DPR changed from ${dprRef.current} to ${currentDpr}, recreating surface`);
      dprRef.current = currentDpr;
      // Force surface recreation on next render
      if (surfaceRef.current) {
        try {
          surfaceRef.current.delete();
        } catch (error) {
          console.warn('Failed to delete surface during DPR change:', error);
        }
        surfaceRef.current = null;
      }
    }
  });

  // Handle window resize and DPR changes
  useEffect(() => {
    const handleResize = () => {
      const currentDpr = window.devicePixelRatio || 1;
      if (currentDpr !== dprRef.current) {
        console.log(`DPR changed from ${dprRef.current} to ${currentDpr} due to resize`);
        dprRef.current = currentDpr;
        // Force surface recreation on next render
        if (surfaceRef.current) {
          surfaceRef.current.delete();
          surfaceRef.current = null;
        }
      }
    };

    window.addEventListener('resize', handleResize);
    return () => window.removeEventListener('resize', handleResize);
  }, []);

  // Render when any relevant prop changes
  useEffect(() => {
    if (!renderingReady) return;
    
    if (CanvasKit && canvasKitInstance) {
      drawTextWithCanvasKit();
    } else {
      console.error('CanvasKit not available - cannot render text');
    }
  }, [text, cursorPosition, fontSize, letterSpacing, renderingReady, isFocused, renderTrigger]);

  const drawTextWithCanvasKit = () => {
    if (!CanvasKit || !canvasKitInstance) {
      console.warn('CanvasKit not available');
      return;
    }

    // Add this check to prevent rendering before fonts are ready
    if (!renderingReady) {
      console.log('Waiting for fonts to load...');
      return;
    }

    const ck = canvasKitInstance;
    const canvasEl = canvasRef.current;
    if (!canvasEl) return;

    const dpr = window.devicePixelRatio || 1;
    dprRef.current = dpr;
    
    // Set canvas dimensions only if they've changed
    if (canvasEl.width !== width * dpr || canvasEl.height !== height * dpr) {
      canvasEl.width = width * dpr;
      canvasEl.height = height * dpr;
      canvasEl.style.width = `${width}px`;
      canvasEl.style.height = `${height}px`;
    }

    // Recreate surface if DPR changed or surface doesn't exist
    if (!surfaceRef.current || surfaceRef.current.width() !== width * dpr || surfaceRef.current.height() !== height * dpr) {
      if (surfaceRef.current) {
        try {
          surfaceRef.current.delete();
        } catch (error) {
          console.warn('Failed to delete old surface:', error);
        }
      }
      try {
        surfaceRef.current = ck.MakeWebGLCanvasSurface(canvasEl);
        console.log(`Surface recreated: ${width * dpr}x${height * dpr} (DPR: ${dpr})`);
      } catch (error) {
        console.error('Failed to create CanvasKit surface:', error);
        return;
      }
    }

    const surface = surfaceRef.current;
    if (!surface) {
      console.error('CanvasKit surface not available');
      return;
    }

    const skCanvas = surface.getCanvas();

    try {
      if (skCanvas.clear) {
        skCanvas.clear(ck.WHITE || CanvasKit.WHITE);
      } else {
        const bgPaint = new ck.Paint();
        bgPaint.setColor(ck.WHITE || CanvasKit.WHITE);
        skCanvas.drawPaint(bgPaint);
        bgPaint.delete && bgPaint.delete();
      }
    } catch (e) {
      console.warn('Failed to clear canvas, continuing...', e);
    }

    if (skCanvas.save) skCanvas.save();
    if (skCanvas.scale) skCanvas.scale(dpr, dpr);

    // Prepare paints
    const textPaint = new ck.Paint();
    textPaint.setAntiAlias(true);
    textPaint.setColor(ck.BLACK);
    // Get current font instance from TextRenderingContext
    const font = getCurrentFont();

    // Safety check - make sure we have a valid font
    if (!font) {
      if (skCanvas.restore) skCanvas.restore();
      return;
    }

    // Measurement helpers
    const measureWidth = (str) => {
      try {
        if (!str || str.length === 0) return 0;
        if (font.getGlyphIDs && font.getGlyphWidths) {
          const glyphs = font.getGlyphIDs(str);
          const widths = font.getGlyphWidths(glyphs);
          return widths.reduce((a, b) => a + b, 0);
        }
      } catch (_) {}
      // Fallback estimate
      return str.length * fontSize * 0.6;
    };

    const spaceWidth = measureWidth(' ');

    // Analyze text and render with dynamic line heights
    const lineInfo = analyzeTextLineBreaks(text);
    let y = fontSize + 10;
    let currentCharIndex = 0;

    for (let lineIndex = 0; lineIndex < lineInfo.length; lineIndex++) {
      const lineData = lineInfo[lineIndex];
      const line = lineData.text;
      let x = 10;

      // Check if cursor should be at the beginning of this line
      // Only draw at beginning if: 1) very start of text, 2) positioned after a line break
      if (isFocused && currentCharIndex === cursorPosition) {
        if (lineIndex === 0 && cursorPosition === 0) {
          // Cursor at very beginning of text
          drawCursor(skCanvas, ck, x, y - fontSize, fontSize);
        } else if (lineIndex > 0) {
          // Cursor at beginning of line after a line break
          // Check if the previous line had a line break
          const prevLine = lineInfo[lineIndex - 1];
          if (prevLine && prevLine.breakType) {
            drawCursor(skCanvas, ck, x, y - fontSize, fontSize);
          }
        }
      }

      // Render each character in the line
      for (let charIndex = 0; charIndex < line.length; charIndex++) {
        const char = line[charIndex];
        const globalCharIndex = currentCharIndex + charIndex;

        // Draw cursor before character if this is the cursor position
        if (isFocused && globalCharIndex === cursorPosition) {
          drawCursor(skCanvas, ck, x, y - fontSize, fontSize);
        }

        // Draw the character
        if (char === ' ') {
          x += spaceWidth + letterSpacing;
        } else {
          try {
            skCanvas.drawText(char, x, y, textPaint, font);
          } catch (error) {
            console.warn('Failed to draw character:', char, error);
          }
          x += measureWidth(char) + letterSpacing;
        }
      }

      // Draw cursor at end of line if this is the cursor position
      const lineEndPosition = currentCharIndex + line.length;
      if (isFocused && lineEndPosition === cursorPosition) {
        // Always draw cursor at end of line content
        drawCursor(skCanvas, ck, x, y - fontSize, fontSize);
      }

      // Move to next line position
      currentCharIndex += line.length + (lineData.breakType ? lineData.breakType.length : 0);
      y += lineData.lineHeight;
    }

    // Draw cursor at very end if cursor is at end of text and it hasn't been drawn yet
    if (isFocused && cursorPosition === text.length && lineInfo.length > 0) {
      const lastLine = lineInfo[lineInfo.length - 1];
      
      // Only draw if the last line has a line break (meaning cursor should be on a new line)
      // OR if the last line has no line break and cursor is at the end
      if (lastLine.breakType) {
        // Last line has a line break, so cursor should be on a new line
        let newLineY = fontSize + 10;
        for (let i = 0; i < lineInfo.length; i++) {
          newLineY += lineInfo[i].lineHeight;
        }
        drawCursor(skCanvas, ck, 10, newLineY - fontSize, fontSize);
      } else {
        // Last line has no line break, cursor should be at the end of the last line
        let lastLineY = fontSize + 10;
        let lastLineX = 10;
        
        // Sum up all line heights except the last one
        for (let i = 0; i < lineInfo.length - 1; i++) {
          lastLineY += lineInfo[i].lineHeight;
        }
        
        // Calculate x position of end of last line
        const lastLineText = lastLine.text || '';
        for (let i = 0; i < lastLineText.length; i++) {
          const char = lastLineText[i];
          if (char === ' ') {
            lastLineX += spaceWidth + letterSpacing;
          } else {
            lastLineX += measureWidth(char) + letterSpacing;
          }
        }
        
        drawCursor(skCanvas, ck, lastLineX, lastLineY - fontSize, fontSize);
      }
    }

    // Restore and flush
    if (skCanvas.restore) skCanvas.restore();
    surface.flush();

    // Cleanup paints to avoid memory leaks (if delete available)
    textPaint.delete && textPaint.delete();
  };

  const drawCursor = (skCanvas, ck, x, y, height) => {
    const cursorPaint = new ck.Paint();
    cursorPaint.setColor(ck.BLACK);
    cursorPaint.setStrokeWidth(1);
    
    try {
      skCanvas.drawLine(x, y, x, y + height, cursorPaint);
    } catch (error) {
      console.warn('Failed to draw cursor:', error);
    }
    
    cursorPaint.delete && cursorPaint.delete();
  };

  // This component only handles the useEffect logic - the actual canvas element
  // is rendered by the parent component
  return null;
};

// Utility function to get current DPR - can be used by other components
export const getCurrentDPR = () => window.devicePixelRatio || 1;

export default TextRenderer;
